﻿using ByteSite.Common;
using Quartz;
using Quartz.Impl;
using Quartz.Impl.Triggers;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Text;
using System.Threading.Tasks;

namespace ByteSite.Service.Quartz
{
    public static class QuartzHelper
    {
        /// <summary>
        /// 缓存任务所在程序集信息
        /// </summary>
        private static Dictionary<string, Assembly> AssemblyDict = new Dictionary<string, Assembly>();

        private static IScheduler scheduler;

        static QuartzHelper()
        {

        }

        /// <summary>
        /// 初始化 
        /// </summary>
        public static void InitScheduler()
        {
            ISchedulerFactory schedulerFactory = new StdSchedulerFactory();
            Task<IScheduler> task_scheduler = schedulerFactory.GetScheduler();
            scheduler = task_scheduler.Result;
        }

        /// <summary>
        /// 依据数据库启动任务
        /// </summary>
        public static void StartScheduler()
        {
            try
            {
                if (!scheduler.IsStarted)
                {
                    //读取数XML文件中的配置，静态缓存
                    var allQuertzXml = TaskList.allTask;
                    if (allQuertzXml != null && allQuertzXml.Count > 0)
                    {
                        foreach (var item in allQuertzXml)
                        {
                            try
                            {
                                //依据配置文件，遍历执行任务 
                                ScheduleJob(item);
                            }
                            catch (Exception e)
                            {
                                Common.LoggerHelper.Error(e.ToString());
                            }
                        }
                    }
                    scheduler.Start();
                }
            }
            catch (Exception ex)
            {
                Common.LoggerHelper.Error("任务调度启动失败！" + ex.ToString());
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="groupName"></param>
        /// <param name="jobName"></param>
        /// <returns></returns>
        public static Task<bool> RemoveSchedule(string groupName, string jobName)
        {
            try
            {
                Task<IScheduler> scheduler = StdSchedulerFactory.GetDefaultScheduler();
                scheduler.Result.PauseTrigger(new TriggerKey(jobName, groupName));
                scheduler.Result.UnscheduleJob(new TriggerKey(jobName, groupName));
                scheduler.Result.DeleteJob(new JobKey(jobName, groupName));
            }
            catch (Exception ex)
            {
                Common.LoggerHelper.Error("任务调度停止失败！" + ex.ToString());
                return Task.FromResult(false);
            }
            Common.LoggerHelper.Info("任务调度停止！");
            return Task.FromResult(true);
        }

        /// <summary>
        /// Job暂停
        /// </summary>
        /// <param name="groupName"></param>
        /// <param name="jobName"></param>
        /// <returns></returns>
        public static Task<bool> PauseSchedule(string groupName, string jobName)
        {
            try
            {
                Task<IScheduler> scheduler = StdSchedulerFactory.GetDefaultScheduler();
                scheduler.Result.PauseJob(new JobKey(groupName, jobName));
            }
            catch (Exception ex)
            {
                Common.LoggerHelper.Error("任务调度暂停失败！" + ex.ToString());
                return Task.FromResult(false);
            }
            return Task.FromResult(true);
        }

        /// <summary>
        /// Job恢复
        /// </summary>
        /// <param name="groupName"></param>
        /// <param name="jobName"></param>
        /// <returns></returns>
        public static Task<bool> ResumeSchedule(string groupName, string jobName)
        {
            try
            {
                Task<IScheduler> scheduler = StdSchedulerFactory.GetDefaultScheduler();
                scheduler.Result.ResumeJob(new JobKey(groupName, jobName));
                
            }
            catch (Exception ex)
            {
                Common.LoggerHelper.Error("任务调度恢复失败！" + ex.ToString());
                return Task.FromResult(false);
            }
            return Task.FromResult(true);
        }

        ///// <summary>
        ///// 启动所有job
        ///// </summary>
        //public static Task<bool> StartSchedule()
        //{
        //    try
        //    {
        //        Task<IScheduler> scheduler = StdSchedulerFactory.GetDefaultScheduler();
        //        if (!scheduler.Result.IsStarted)
        //            scheduler.Result.Start();
        //    }
        //    catch (Exception ex)
        //    {
        //        Common.LoggerHelper.Error("启动所有任务调度失败！" + ex.ToString());
        //        return Task.FromResult(false);
        //    }
        //    return Task.FromResult(true);
        //}

        /// <summary>
        /// 停止所有job
        /// </summary>
        public static Task<bool> ShutdownSchedule()
        {
            try
            {
                Task<IScheduler> scheduler = StdSchedulerFactory.GetDefaultScheduler();
                if(!scheduler.Result.IsShutdown)
                    scheduler.Result.Shutdown();
            }
            catch (Exception ex)
            {
                Common.LoggerHelper.Error("停止所有任务调度失败！" + ex.ToString());
                return Task.FromResult(false);
            }
            return Task.FromResult(true);
        }

        /// <summary>
        /// 查询一个job
        /// </summary>
        /// <param name="groupName"></param>
        /// <param name="jobName"></param>
        /// <returns></returns>
        public static Task<string> GetSchedule(string groupName, string jobName)
        {
            try
            {
                Task<IScheduler> scheduler = StdSchedulerFactory.GetDefaultScheduler();
                Task<ITrigger> trigger = scheduler.Result.GetTrigger(new TriggerKey(jobName, groupName));
                if (trigger.Result != null)
                {
                    Task<IJobDetail> jobDetail = scheduler.Result.GetJobDetail(new JobKey(jobName, groupName));
                    if (jobDetail.Result != null)
                    {
                        string json = JsonHelper.ObjectToJSON(new { GroupName = groupName, JobName = jobName, DataType = jobDetail.Result.JobType.AssemblyQualifiedName + "," + jobDetail.Result.JobType.FullName});
                        return Task.FromResult(json);
                    }
                    else
                    {
                        Common.LoggerHelper.Error("该Quartz-Job不存在");
                        return Task.FromResult("该Quartz-Job不存在");
                    }
                }
                else
                {
                    Common.LoggerHelper.Error("该Quartz-Job的触发器不存在");
                    return Task.FromResult("该Quartz-Job的触发器不存在");
                }
            }
            catch (Exception ex)
            {
                Common.LoggerHelper.Error("查询任务调度不存在" + ex.Message);
                return Task.FromResult("查询任务调度不存在" + ex.Message);
            }
        }

        /// <summary>
        /// 中止所有的任务调度
        /// </summary>
        public static void StopSchedule()
        {
            try
            {
                //判断调度是否已经关闭
                if (!scheduler.IsShutdown)
                {
                    //等待任务运行完成
                    scheduler.Shutdown(true);
                    Common.LoggerHelper.Info("任务调度停止！");
                }
            }
            catch (Exception ex)
            {
                Common.LoggerHelper.Error("任务调度停止失败！" + ex.ToString());
            }
        }

        /// <summary>
        /// 启用任务
        /// <param name="task">任务信息</param>
        /// <param name="isDeleteOldTask">是否删除原有任务</param>
        /// <returns>返回任务trigger</returns>
        /// </summary>
        static void ScheduleJob(Entitys.QuartzTask task)
        {
            //验证是否正确的Cron表达式
            if (ValidExpression(task.cron))
            {
                //监测是否存在该任务
                JobKey jk = new JobKey(task.id.ToString(), "default");

                Task<bool> check = scheduler.CheckExists(jk);
                if (check.Result)
                {
                    scheduler.DeleteJob(jk);
                }

                IJobDetail job = new JobDetailImpl(task.id.ToString(), "default", GetClassInfo(task.assembly_name, task.assembly_classname));

                //添加任务执行参数
                job.JobDataMap.Add("TaskParam", task.assembly_params);

                CronTriggerImpl trigger = new CronTriggerImpl();
                trigger.CronExpressionString = task.cron;
                trigger.Name = task.id.ToString();
                trigger.Group = "default";
                trigger.Description = task.name;
                scheduler.ScheduleJob(job, trigger);
                if (task.status == (byte)0 || DateTime.Now > task.end_time)  //中止任务
                    scheduler.PauseJob(jk);
            }
            else
            {
                throw new Exception(task.cron + "不是正确的Cron表达式,无法启动该任务!");
            }
        }

        /// 获取类的属性、方法  
        /// </summary>  
        /// <param name="assemblyName">程序集</param>  
        /// <param name="className">类名</param>  
        static Type GetClassInfo(string assemblyName, string className)
        {
            try
            {
                assemblyName = Common.FileHelper.GetAbsolutePath(assemblyName + ".dll");
                Assembly assembly = null;
                if (!AssemblyDict.TryGetValue(assemblyName, out assembly))
                {
                    assembly = Assembly.LoadFrom(assemblyName);
                    AssemblyDict[assemblyName] = assembly;
                }
                Type type = assembly.GetType(className, true, true);
                return type;
            }
            catch (Exception ex)
            {
                throw ex;
            }
        }

        /// <summary>
        /// 校验字符串是否为正确的Cron表达式
        /// </summary>
        /// <param name="cronExpression">带校验表达式</param>
        /// <returns></returns>
        static bool ValidExpression(string cronExpression)
        {
            return CronExpression.IsValidExpression(cronExpression);
        }

    }
}